package com.linln.admin.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.linln.admin.config.Result;
import com.linln.admin.config.SignUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;

/**
 * 签名认证拦截器
 */
@Component
public class SignInterceptor implements HandlerInterceptor {

    @Value(("${securitys.key}"))
    private String key;

    private static final Logger logger = LoggerFactory.getLogger(SignInterceptor.class);

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
    }

    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {

        String url = request.getRequestURI();
        if (url.contains("/api")  && !url.contains("/api/uploads/images") && !url.contains("/api/js/wechat/pay/notify") && !url.contains("/api/js/wechat/refund/callback")){
            String sign = request.getHeader("sign");
            String devValue = key;
            Map<String, String[]> parameterMap = request.getParameterMap();
            String body = null;
            String bodys = "";
            body = new RepeatedlyRequestWrapper(request).getBodyString();
            Map<String, Object> parse = (Map<String, Object>)JSON.parse(body);
            if (!Objects.isNull(parse)){
                if (parse.size()>0){
                    TreeMap<String, Object> temp = new TreeMap<>();
                    for (Map.Entry<String,Object> ex:parse.entrySet()) {
                        String oo = String.valueOf(ex.getValue());
                        if (oo.contains("[")||oo.contains("【")||oo.contains("{")){
                        }else{
                            //判断参数值类型是否是整形或字符串
                            Boolean type = getType(oo);
                            if (type){
                                temp.put(ex.getKey(),ex.getValue());
                            }
                        }
                    }
                    bodys = getUrlPram(temp);
                }
            }


            if (!Objects.isNull(parameterMap)){

                if (parameterMap.size()>0){
                    bodys = "";
                    TreeMap<String, Object> tt = new TreeMap<>();
                    for (Map.Entry<String,String[]> ex:parameterMap.entrySet()) {
                        String[] oo = ex.getValue();
                        String key1 = ex.getKey();
                        if (oo.length>0){
                            String s = oo[0];
                            if (s.contains("[")||s.contains("【")||s.contains("{")){
                            }else{
                                //判断参数值类型是否是整形或字符串
                                Boolean type = getType(s);
                                if (type){
                                    tt.put(key1,s);
                                }
                            }
                        }
                    }
                    if (tt.size()>0){
                        bodys = getUrlPram(tt);
                    }
                }
            }
            Result result = checkSignIsValid(sign);
            if (result != null) {
                writer(response, result);
                logger.info("签名认证失败：" + JSONObject.toJSONString(result));
                return false;
            }

            try {
                boolean validPostRequest = SignUtils.isValidRequest(sign, bodys, devValue, request.getMethod());
                if (!validPostRequest) {

                    writer(response, Result.failure(206, "签名无效"));
                    logger.info("{}  认证失败 参数:sign = {} , url = {} ,请求参数 = {}",
                            request.getMethod(),
                            sign,
                            url,
                            bodys
                            );

                    return false;
                }
            } catch (Exception e) {
                writer(response, Result.failure(500, e.getMessage()));
                return false;
            }

            return true;
        }else{
            return true;
        }
    }

    public Boolean getType(Object object) {
        if (object == null) {
            return false;
        }
        if (object instanceof BigDecimal) {
            return true;
        }
        if (object instanceof BigInteger) {
            return true;
        }
        if (object instanceof Long) {
            return true;
        }
        if (object instanceof Integer) {
            return true;
        }
        if (object instanceof String) {
            return true;
        }
        return false;
    }

    private void writer(HttpServletResponse response, Result restResult) {
        try {
            response.setContentType("application/json; charset=utf-8");
            response.setHeader("Cache-Control","no-cache");
            response.setCharacterEncoding("utf-8");
            response.getWriter().write(JSONObject.toJSONString(restResult));
            response.getWriter().flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
//        finally {
//            response.getWriter().close();
//        }

    }

    private String getUrlPram(TreeMap<String, Object> tt) {

        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> es:tt.entrySet()) {
            String key = es.getKey();
            Object value = es.getValue();
            if (sb.length() == 0) {
                sb.append(key + "=" + value);
            } else {
                sb.append("&" + key + "=" + value);
            }
        }

        return sb.toString();
    }

    private Result checkSignIsValid(
            String sign) {

        if (StringUtils.isBlank(sign)) {
            return Result.failure(201, "签名有误");
        }

        return null;
    }
}
